// ServerDlg.cpp : implementation file
//

#include "stdafx.h"
#include "Server.h"
#include "ServerDlg.h"
#include "Config.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

char* dataBuff;
int fOffset;
CProgressCtrl* m_progress;

CString _savedFileName(_T(""));

// CServerDlg dialog

static int GetInteger(char* buff, int index)
{
	char s[4];
	strncpy(s, buff + index, 4);
	return atoi(s);
}

static int GetClientIndex(int* arr, int n, int clientID)
{
	for(int i=0; i<n; i++)
	{
		if(arr[i] == clientID)
			return i;
	}
	return -1;
}

CServerDlg::CServerDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CServerDlg::IDD, pParent)
	, m_clientCounter(0)
	, m_port(0)
	, m_ipAddress(_T(""))
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
	dataBuff = NULL;
	m_fileBuffer = NULL;
}

void CServerDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_CMB_CLIENT_LIST, m_cmbClientList);
}

BEGIN_MESSAGE_MAP(CServerDlg, CDialog)
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	//}}AFX_MSG_MAP
	ON_BN_CLICKED(IDC_BTN_STARTSERVER, &CServerDlg::OnBnClickedBtnStartserver)
	ON_BN_CLICKED(IDC_BTN_STOP_SERVER, &CServerDlg::OnBnClickedBtnStopServer)
	ON_BN_CLICKED(IDC_BTN_EXIT, &CServerDlg::OnBnClickedBtnExit)
END_MESSAGE_MAP()


// CServerDlg message handlers

BOOL CServerDlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	// Set the icon for this dialog.  The framework does this automatically
	//  when the application's main window is not a dialog
	SetIcon(m_hIcon, TRUE);			// Set big icon
	SetIcon(m_hIcon, FALSE);		// Set small icon

	m_port = 2000;
	m_ipAddress = _T("127.0.0.1");
	m_clientCounter = 0;
	for(int i=0; i<MAX_CLIENTS; i++)
	{
		m_clientIDArr[i] = -1;
	}
	m_serverSocket.pDlg = this;

	GetDlgItem(IDC_BTN_STARTSERVER)->EnableWindow(TRUE);
	GetDlgItem(IDC_BTN_STOP_SERVER)->EnableWindow(FALSE);


#ifdef USE_DEBUG
	int offset = 12;
	byte buff[BUFF_SIZE];
	memset(buff, 23, BUFF_SIZE);
	/*
	WriteINT32(76543, buff, offset);
	int hhh = ReadINT32(buff, offset);
	offset += 4;
	WriteINT8(175, buff, offset);
	byte bbb = ReadINT8(buff, offset);
	offset += 1;
	WriteINT16(23568, buff, offset);
	short sss = ReadINT16(buff, offset);
	*/
/*
	int kkkk = sizeof(int);
	m_package.type = 1;
	m_package.action = 2;
	m_package.dataSize = 12121;
	m_package.WriteToBuffer(buff);
*/

	byte* ch = (byte*)m_szBuff;
	int kkk = sizeof(ch);
	int kkk1 = sizeof(m_szBuff);
OutputDebugString(_T("%%%%%%%%%%%%%%%%%%%%%"));
	memcpy(ch, buff, BUFF_SIZE);
OutputDebugString(_T("@@@@@@@@@@@@@@@@@@@@@@@@@"));
#endif
	
	m_progress = ((CProgressCtrl*)GetDlgItem(IDC_PROGRESS));
	m_receiveSize = 0;
/*
	m_progress->SetRange(0, 1000);
	m_progress->SetStep(200);
	m_progress->StepIt();
	for(int i=0; i<8; i++)
	{
		m_progress->SetStep(100);
		m_progress->StepIt();
	}
*/	

	return TRUE;  // return TRUE  unless you set the focus to a control
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CServerDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // device context for painting

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// Center icon in client rectangle
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// Draw the icon
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialog::OnPaint();
	}
}

// The system calls this function to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CServerDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}


void CServerDlg::OnBnClickedBtnStartserver()
{
	if( AfxSocketInit() == FALSE)
	{ 
		AfxMessageBox(_T("Failed to Initialize Sockets")); 
		return; 
	}

	if(m_serverSocket.Create(m_port) == FALSE)
	{
		MessageBox(_T("Failed to create"));
		return;
	}

	if(m_serverSocket.Listen() == FALSE)
	{
		MessageBox(_T("Failed"));
		m_serverSocket.Close();
		return;
	}

	GetDlgItem(IDC_BTN_STARTSERVER)->EnableWindow(FALSE);
	GetDlgItem(IDC_BTN_STOP_SERVER)->EnableWindow(TRUE);
	OutputDebugString(_T("[Server Dlg]: Server started"));
}

bool CServerDlg::OnAccept()
{
	OutputDebugString(_T("[Server Dlg] Accepted"));
#ifdef USE_PACKAGE	
	int index = 0;
	m_serverSocket.Accept(m_clientSocketArr[index]);
	m_clientIDArr[index] = 1000+m_clientCounter;
	m_clientSocketArr[index].pDlg = this;
	char str[256];
	m_clientCounter++;
	m_package.type = TYPE::CHATTING;
	m_package.action = ACTION::CHAT_SIGNIN;
	WriteINT32(m_clientIDArr[index], m_package.data, 0);

	int dSize = m_package.WriteToBuffer((byte*)m_szBuff);
	SendToAll();
	//CString str(_T("NO Accepted Clients: "));	
	//SetDlgItemTextA(this->GetSafeHwnd(), IDC_STATIC_CLIENT_NO, str);

	return true;
#else	//USE_PACKAGE
	if(m_clientCounter < MAX_CLIENTS)
	{
		int index = -1;
		for(int i=0; i<MAX_CLIENTS; i++)
		{
			if(m_clientIDArr[i] < 0)
			{
				index = i;
				break;
			}
		}
		if(index >= 0)
		{
			m_serverSocket.Accept(m_clientSocketArr[index]);
			m_clientIDArr[index] = 1000+m_clientCounter;
			m_clientSocketArr[index].pDlg = this;

			char str[256];
/*
			char str[256];
			sprintf(str, "%d", m_clientIDArr[index]);
			m_clientSocketArr[index].Send(str, sizeof(str));
*/
			//m_clientSocketArr[index].Send(szBuff, sizeof(m_szBuff));
			
			m_clientCounter++;
			sprintf(m_szBuff, "%d%d%d", 1, m_clientCounter,m_clientIDArr[index]);
			
			for(int i=0; i<m_clientCounter; i++)
			{
				sprintf(str,"%d",m_clientIDArr[i]);
				strcat(m_szBuff, str);
			}
			SendToAll();
			OutputDebugString(_T("[Server Dlg] Accepted"));
			//CString str(_T("NO Accepted Clients: "));
			
			sprintf(str, "%s %d", "NO Accepted Clients: ", m_clientCounter);
			SetDlgItemTextA(this->GetSafeHwnd(), IDC_STATIC_CLIENT_NO, str);
		}
		return true;
	}
#endif	//USE_PACKAGE
	OutputDebugString(_T("[Server Dlg] Server can't accept"));
	return false;
}

void CServerDlg::OnBnClickedBtnStopServer()
{
	
	GetDlgItem(IDC_BTN_STARTSERVER)->EnableWindow(TRUE);
	GetDlgItem(IDC_BTN_STOP_SERVER)->EnableWindow(FALSE);
	OutputDebugString(_T("[Server Dlg]: Server stoped"));
}

void CServerDlg::OnBnClickedBtnExit()
{
	AfxGetMainWnd()->PostMessage(WM_CLOSE);
}

bool CServerDlg::OnReceive(char* buff, int size)
{
	OutputDebugString(_T("[Server Dlg] 111111111111111111111"));
	/*
	Package package;
	package.LoadData(buff);
	int clientID = -1;
	clientID = buff[0] - '0';
	for(int i=1; i<4; i++)
	{
		clientID *= 10;
		clientID += buff[i] - '0';
	}
	CString str;
	GetDlgItemText(IDC_EDIT_RECEIVE_MSG, str);
	CString s(buff+4);
	bool isClientClose = false;
	if(s.Compare(_T("exit")) == 0)
	{
		isClientClose = true;
	}
	str.Append(s);
	str += "\r\n";
	//str.Append(_T("\r\n"));
	GetDlgItem(IDC_EDIT_RECEIVE_MSG)->SetWindowText(str);
	char sStr[1000];
	strcpy(sStr, "Da nhan duoc");
	//m_serverSocket.Send(sStr, sizeof(sStr));
	int index = -1;
	for(int i=0; i<MAX_CLIENTS; i++)
	{
		if(clientID == m_clientIDArr[i])
		{
			index = i;
			break;
		}
	}
	if(index >= 0)
	{
		if(isClientClose)
		{
			m_clientSocketArr[index].ShutDown(2);
			m_clientSocketArr[index].Close();
			m_clientIDArr[index] = -1;
			m_clientCounter--;
		}
		else
		{
			m_clientSocketArr[index].Send(sStr, sizeof(sStr));
		}
	}
	*/
	int clientID_src = -1;
	int clientID_dest = -1;
	//char msg[1000];
	m_package.LoadData((byte*)m_szBuff);
	OutputDebugString(_T("package load data finish!"));
	switch(m_package.type)
	{
		case TYPE::CHATTING:	// chatting
			{
				switch(m_package.action)
				{
					case ACTION::CHAT_SIGNIN:	// client sign in
						{
							int k = ReadINT32((byte*)m_szBuff, m_package.dataOffset);
							//int index = GetClientIndex(m_clientIDArr, MAX_CLIENTS, clientID);
							int index = GetClientIndex(m_clientIDArr, MAX_CLIENTS, k);
							for(int i=k; i<MAX_CLIENTS-1; i++)
							{
								m_clientIDArr[i] = m_clientIDArr[i+1];
							}
							m_clientIDArr[MAX_CLIENTS-1] = -1;
							SendToAll();
						}
						break;
					case ACTION::CHAT_SEND_MESSAGE:	// client send message
						{
							m_package.dataOffset = 6;
							clientID_src = ReadINT32((byte*)m_szBuff, m_package.dataOffset);
							clientID_dest = ReadINT32((byte*)m_szBuff, m_package.dataOffset + 4);
							//strcpy(msg, m_szBuff + 9);
							SendToClient(clientID_dest);
							break;
						}
					case ACTION::CHAT_SIGNOUT:	// client logout
						break;
					default:
						break;
				}
			}
			break;
		case TYPE::FILE_TRANSFER:	// sending file
			{
				switch(m_package.action)
				{
					case ACTION::FILE_HEADER:
						{
							OutputDebugString(_T("[Server Dlg]: FILE_HEADER"));
							m_package.dataOffset = 6;
							int offset = m_package.dataOffset;
							offset = 6;
							m_fileSize = ReadINT32((byte*)m_szBuff, offset);
							offset += 4;
							strcpy(m_fileName, (char*)(m_szBuff + offset));
							int k;
							CString str(_T("Nhan file"));
							_savedFileName.Format(_T("%S"), m_fileName);
							k = _savedFileName.ReverseFind('\\');
							_savedFileName = _savedFileName.Mid(k+1);
							//sprintf(str, "File Name: %s\nSize: %d", m_fileName, m_fileSize);
							str.Format(_T("File Name: %S\nSize: %d"), m_fileName, m_fileSize);
							m_progress->SetRange32(0, m_fileSize);
							//MessageBox(_T("Nhan file"));
							//MessageBox(str);

							
							k = _savedFileName.ReverseFind('.');
							CString file_type = _savedFileName.Mid(k);
							if(MessageBox(str, _T("Do you save file?"), MB_YESNO) == IDYES)
							{
								CFileDialog dlg(FALSE);
								
								dlg.m_ofn.lpstrFilter = file_type;
								dlg.m_ofn.lpstrTitle=_T("Save file");
								
								if(dlg.DoModal() == IDOK)
								{
									_savedFileName = dlg.GetPathName();
									_savedFileName += file_type;
								}
								else
								{
									_savedFileName = _T("C:\\") + _savedFileName;
								}

								OutputDebugString(_T("[Server Dlg]: Server accept file!"));
								m_package.type = TYPE::FILE_TRANSFER;
								m_package.action = ACTION::FILE_START;
								m_package.WriteToBuffer((byte*)m_szBuff);
								// m_clientSocketArr[0].Send(m_szBuff, sizeof(m_szBuff));
								m_clientSocketArr[0].Send(m_szBuff, BUFF_SIZE);

							}
							else
							{
								OutputDebugString(_T("[Server Dlg]: Server do not recive file!"));
								m_package.type = TYPE::FILE_TRANSFER;
								m_package.action = ACTION::FILE_STOP;
								m_package.WriteToBuffer((byte*)m_szBuff);
								// m_clientSocketArr[0].Send(m_szBuff, sizeof(m_szBuff));
								m_clientSocketArr[0].Send(m_szBuff, BUFF_SIZE);
								break;
							}
							OutputDebugString(_T("[Server Dlg]: FILE_HEADER - end"));
							//memcpy(m_fileName, m_szBuff + offset, m_package.dataSize - 4);
						}
						break;
					case ACTION::FILE_START:
						{
							OutputDebugString(_T("[Server Dlg]: FILE_START"));
							//m_fileBuffer = new byte[m_fileSize];
							//m_file = fopen("C:\\tmp\\receive.dat", "wb");
							char fName[256];
							sprintf(fName, "%S", (char*)_savedFileName.GetBuffer());
							m_file = fopen(fName, "wb");
							fOffset = 0;

							m_package.type = TYPE::FILE_TRANSFER;
							m_package.action = ACTION::FILE_SEND;
							m_package.WriteToBuffer((byte*)m_szBuff);
							m_clientSocketArr[0].Send(m_szBuff, sizeof(m_szBuff));
							OutputDebugString(_T("[Server Dlg]: FILE_START - end"));
//							m_progress->SetRange(0, m_fileSize);
							
						}
						break;
					case ACTION::FILE_SEND:
						{
							OutputDebugString(_T("[Server Dlg]: FILE_SEND"));
							m_package.LoadData((byte*)m_szBuff);
							m_package.dataOffset = 6;
							//if(fOffset < m_fileSize)
							if(true)
							{
								try
								{
									OutputDebugString(_T("[Server Dlg]: Writting file..."));
									//fwrite(m_package.data, 1, BLOCK_SIZE, m_file);
									fwrite(m_package.data, 1, m_package.dataSize, m_file);

									//int step = (int)(m_package.dataSize*100.0/m_fileSize);
									//m_progress->SetStep(m_package.dataSize);
									m_progress->SetStep(m_package.dataSize);
									m_progress->StepIt();
									//memcpy(m_fileBuffer + fOffset, m_package.data, m_package.dataSize);
									m_package.type = TYPE::FILE_TRANSFER;
									m_package.action = ACTION::FILE_SEND;
									m_package.WriteToBuffer((byte*)m_szBuff);
									//m_clientSocketArr[0].Send(m_szBuff, sizeof(m_szBuff));
									int kkk = m_clientSocketArr[0].Send(m_szBuff, BUFF_SIZE);
									char str[256];
									sprintf(str, ">>>>>[Server Dlg]: Send size = %d", kkk);
									OutputDebugStringA(str);
									fOffset += m_package.dataSize;
								}
								catch (CMemoryException* e)
								{
									OutputDebugString(_T("[ERROR]: CMemoryException"));
								}
								catch (CFileException* e)
								{
									OutputDebugString(_T("[ERROR]: CFileException"));
								}
								catch (CException* e)
								{
									OutputDebugString(_T("[ERROR]: ^^^^*****^^^^"));
								}
							}
							else
							{
								OutputDebugString(_T("[Server Dlg]: Finish send file"));
							}
							OutputDebugString(_T("[Server Dlg]: FILE_SEND - end"));
						}
						break;
					case ACTION::FILE_STOP:
						{
							OutputDebugString(_T("[Server Dlg]: FILE_STOP"));
							/*
							FILE *f = fopen("C:\\receive.dat", "w");
							setbuf(f, (char*)m_fileBuffer);
							fclose(f);
							*/
							fclose(m_file);
							MessageBox(_T("Finish!"));
							OutputDebugString(_T("[Server Dlg]: FILE_STOP - end"));
						}
						break;
					default:
						break;
				}
			}
			break;
		default:
			break;
	}
	/*
	switch(m_szBuff[0])
	{
		case '1':
			OutputDebugString(_T("[Server Dlg]: Receive sign in!"));
			break;
		case '2':
			{
				int k = GetInteger(m_szBuff, 1);
				//int index = GetClientIndex(m_clientIDArr, MAX_CLIENTS, clientID);
				int index = GetClientIndex(m_clientIDArr, MAX_CLIENTS, k);
				for(int i=k; i<MAX_CLIENTS-1; i++)
				{
					m_clientIDArr[i] = m_clientIDArr[i+1];
				}
				m_clientIDArr[MAX_CLIENTS-1] = -1;
				SendToAll();
			}
			break;
		case '3':
			clientID_src = GetInteger(m_szBuff, 1);
			clientID_dest = GetInteger(m_szBuff, 5);
			//strcpy(msg, m_szBuff + 9);
			SendToClient(clientID_dest);
			break;
		case '4':	//ask for received file
			{
				char fName[256];

				strcpy(fName, m_szBuff + 5);
				
				CString str(fName);

				strcpy(m_fileName, "C:\\");

				int k = str.ReverseFind('\\');
				if(k > 0)
				{
					str = str.Mid(k+1);
					strcat(m_fileName, fName + k + 1);
				}
				k = GetInteger(m_szBuff, 1);
				if (MessageBox(str, _T("Receive file from client?"), MB_YESNO) == IDYES)
				{
					OutputDebugString(_T("[Server Dlg] Accept file from client"));
					strcpy(m_szBuff, "5-OK-");
					
				}
				else
				{
					strcpy(m_szBuff, "5-NO-");
					OutputDebugString(_T("222222222222222222222222222222"));
				}
				SendToClient(k);
			}
			break;
		case '5':
			{
				if(strncmp(m_szBuff + 1, "START", 5) == 0)
				{
					char str[256];
					strcpy(str, m_szBuff + 10);
					long lSize = atol(str);
					
					//strcpy(m_fileName, m_szBuff + 10);
					m_fileSize = atol(m_fileName);
					
					
					OutputDebugString(_T("RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR"));
				}
				else if(strncmp(m_szBuff + 1, "DATA", 4) == 0)
				{
				}
			}
			break;
		default:
			break;
	}
	*/
	return true;
}

void CServerDlg::Proccess(char* buff)
{
	/*
	Package package;
	package.LoadData(buff);
	int state = (int)(package.state[0] - '0');

	switch(state)
	{
		case STATE_SIGN_IN:
			break;
		case STATE_SIGN_OUT:
			break;
		case STATE_SEND:
			break;
		default:
			break;
	}
	*/
	/*
	char s[PACKAGE_INDEX_LEN.ACTION];
	int state = buff[PACKAGE_INDEX.STATE];
	int action = atoi(strncpy(s,buff,PACKAGE_INDEX_LEN.ACTION));
	*/
}

void CServerDlg::SendToAll(void)
{
	for(int i=0; i<MAX_CLIENTS; i++)
	{
		if(m_clientIDArr[i] >= 0)
		{
			// m_clientSocketArr[i].Send(m_szBuff, 1000);
			m_clientSocketArr[i].Send(m_szBuff, BUFF_SIZE);
		}
	}
}

void CServerDlg::SendToClient(int clientID)
{
	int index = GetClientIndex(m_clientIDArr, MAX_CLIENTS, clientID);
	//f(m_clientIDArr[clientID] >= 0)
	if(index >= 0)
	{
		// m_clientSocketArr[index].Send(m_szBuff, 1000);
		m_clientSocketArr[index].Send(m_szBuff, BUFF_SIZE);
	}
}

void CServerDlg::OnCancel()
{
	// TODO: Add your specialized code here and/or call the base class
	if(dataBuff != NULL)
	{
		delete dataBuff;
		dataBuff = NULL;
	}

	if(m_fileBuffer != NULL)
	{
		delete m_fileBuffer;
		m_fileBuffer = NULL;
	}
	CDialog::OnCancel();
}
